﻿using System;
using System.Linq;
using SLNGP.Common.Extensions;
using SLNGP.Core.Individuals;
using FitnessNumber = System.Int32;

namespace SLNGP.Core.Fitness
{
    public abstract class FitnessFunction : IFitnessFunction
    {
        public FitnessFunction()
        {
            FitnessFunctionOrder = FitnessFunctionOrder.HigherIsBetter;
        }

        public abstract void Evaluate(IGeneration generationToEvaluate);

        public FitnessFunctionOrder FitnessFunctionOrder { get; set; }

        public int GetEffectiveFitness(FitnessNumber ActualFitness, IGeneration generation)
        {
            if (FitnessFunctionOrder == FitnessFunctionOrder.HigherIsBetter)
                return ActualFitness;
            else if (FitnessFunctionOrder == FitnessFunctionOrder.LowerIsBetter)
            {
                return generation.FitnessData.As<FitnessNumber>() - ActualFitness;
            }
            throw new GeneticProgrammingException(FitnessFunctionOrder + " is not a recgonized value.");
        }

        public void InitializeForEffectiveFitness(IGeneration generation)
        {
            if (FitnessFunctionOrder == FitnessFunctionOrder.LowerIsBetter)
            {
                FitnessNumber maximumFitnessForHighestFitnessIndividual = generation.Max(i => i.Fitness.As<FitnessNumber>());
                generation.FitnessData = maximumFitnessForHighestFitnessIndividual;
            }
        }

        public bool IsBigger(object fitness1, object fitness2)
        {
            if (FitnessFunctionOrder == FitnessFunctionOrder.HigherIsBetter)
            {
                return fitness1.As<FitnessNumber>() > fitness2.As<FitnessNumber>();
            }
            else if (FitnessFunctionOrder == FitnessFunctionOrder.LowerIsBetter)
            {
                return fitness1.As<FitnessNumber>() < fitness2.As<FitnessNumber>();
            }
            else
            {
                throw new GeneticProgrammingException(FitnessFunctionOrder + " is not a recgonized value.");
            }
        }
    }
}